# -*- coding: utf-8 -*-
"""
@Time: 2021/12/6 9:34
@Author: 鹄望潇湘
@File: my_submission.py
@desc: 
"""
import random
import math
import time

import numpy as np
from my_submission.battle_system import TeamDispatcher


class BaseSubmission:

    def __init__(self, team_name, player_names):
        self.team_name = team_name
        self.player_names = player_names

    def get_actions(self, obs):
        '''
        Overview:
            You must implement this function.
        '''
        raise NotImplementedError


class MySubmission(BaseSubmission):

    def __init__(self, team_name, player_names):
        super(MySubmission, self).__init__(team_name, player_names)
        self.now_fps = 0
        self.foods_mask = None
        self.is_stop = False

        self.last_spore = dict()
        self.clone_num = dict()
        for item in player_names:
            self.last_spore[item] = 0
            self.clone_num[item] = 1

        self.dispatcher = TeamDispatcher(team_name, player_names)

    def find_most_food_metric(self, status: dict, global_state: dict):
        """
        寻找可见范围内食物最多的区域，返回一个坐标，以该坐标为中心的区域内是食物最多的

        :param status: 该玩家所能获得的所有信息
        :return: (int, int)
        """

        target_x, target_y = 0, 0
        w_metric, h_metric = 300, 300  # 把视野内的区域划分成300x300的区域
        x2, y2 = global_state['border']  # 视野矩形坐标
        w, h = x2, y2
        foods_number = np.zeros(shape=(h_metric, w_metric), dtype=np.int16)

        #  统计哪块区域的食物最多
        for food in status['overlap']['food']:
            belong_x = int(food[0] // (w / w_metric))
            belong_y = int(food[1] // (w / h_metric))
            foods_number[belong_x, belong_y] = foods_number[belong_x, belong_y] + 1

        #  计算不同区域的权重，距离中心越远，权重越小
        if self.foods_mask is None:
            self.foods_mask = np.ones(shape=(h_metric, w_metric), dtype=np.float)
            center_x, center_y = w_metric / 2, h_metric / 2
            for row in range(0, h_metric):
                for col in range(0, w_metric):
                    dis = self.get_distance((row, col), (center_x, center_y))
                    if dis == 0:
                        dis = 1
                    self.foods_mask[row, col] = 1 / dis
        #  将权重和区域的食物数量相乘作为到达该区域的收益
        foods_number = foods_number * self.foods_mask
        #  寻找收益最大的区域
        s = np.argmax(foods_number)
        max_x = s // h_metric
        max_y = s % w_metric
        target_x = max_x * (w / w_metric) + w / (2 * w_metric)
        target_y = max_y * (h / h_metric) + h / (2 * h_metric)
        return target_x, target_y

    def get_actions(self, obs):
        self.now_fps = self.now_fps + 1
        global_state, player_states = obs

        self.dispatcher.state_perception(global_state, player_states)
        return self.dispatcher.get_action(global_state, player_states)

        """
        result = {}
        for name in self.player_names:
            act = self.get_action_from_status(player_states[name], global_state, name)
            if (act[0] == 0 and act[1] == 0) or (act[0] == -0 and act[1] == -0):
                act[0] = -1
                act[1] = -1
            result[name] = act
        return result
        """

    def get_direction_from_feature(self, feature) -> (float, float):
        y1 = -1
        x1 = -1
        x2 = -1
        y2 = -1
        for i in range(0, 300):
            sum1 = np.sum(feature[i, :])
            sum2 = np.sum(feature[:, i])
            if sum1 > 0:
                if y1 == -1:
                    y1 = i
                else:
                    y2 = i
            if sum2 > 0:
                if x1 == -1:
                    x1 = i
                else:
                    x2 = i
        x1 = x1 - 150
        x2 = x2 - 150
        y1 = 150 - y1
        y2 = 150 - y2

        return ((x1 + x2) / -2, (y1 + y2) / -2)
        pass

    def get_action_from_status(self, states, global_state, player_name):

        my_name = player_name
        if len(states['overlap']['clone']) - self.clone_num[my_name] > 3:
            self.last_spore[my_name] = int(time.time())
        self.clone_num[my_name] = len(states['overlap']['clone'])

        center_x = 0
        center_y = 0
        min_clone = [0, 0, 1000000]
        max_clone = [0, 0, 0]
        sum_weight = 0

        for item in states['overlap']['clone']:
            sum_weight = sum_weight + item[2]
            center_x = center_x + item[0]
            center_y = center_y + item[1]
            if item[2] < min_clone[2]:
                min_clone = item
            if item[2] > max_clone[2]:
                max_clone = item

        if self.is_stop and len(states['overlap']['clone']) > 5:
            if random.randint(-1, 3) < 0:
                return [None, None, 0]
            else:
                return [None, None, -1]

        if len(states['overlap']['clone']) > 8 and max_clone[2] - min_clone[2] < max_clone[2] and \
                global_state['leaderboard'][self.team_name] > 1000 and min_clone[2] > 10 and \
                time.time() - self.last_spore[my_name] > 10:
            if self.is_stop:
                return [None, None, 0]
            else:
                self.is_stop = True
                return [None, None, 2]
            pass
        self.is_stop = False

        if self.now_fps % 10 == 0 and self.now_fps < 100:
            return [-1, -1, 4]
        if self.now_fps % 50 == 0 and 300 > self.now_fps > 100:
            return [-1, -1, 4]
        if self.now_fps % 80 == 0 and len(states['overlap']['clone']) < 8 and random.randint(-1, 2) < 0:
            return [-1, -1, 4]

        # 分裂策略
        channels = states["feature_layers"]
        channels = channels[0: len(channels) - 3]
        target_channel = []  # 保存全部视图在本player视野范围内的其他玩家的球
        food_x = 0
        food_y = 0
        """
        for item in channels:
            square = np.sum(item)
            if square == 0:
                continue
            if np.sum(item[0, :])+np.sum(item[:, 0])+np.sum(item[299, :])+\
                    np.sum(item[:, 299]) > 0:
                continue
            target_channel.append(item)
        for item in target_channel:
            square = np.sum(item)
            R2 = math.sqrt(square/math.pi)
            pos = self.get_direction_from_feature(item)

            for clones in states['overlap']['clone']:
                R1 = clones[2]
                dis = self.get_distance((pos[0], pos[1]), (0, 0))
                if R2<0.5*R1 and dis<2.5*R1-R2:
                    return [pos[0], pos[1], 4]
        pass
        """
        if random.randint(-5, 1) < 0:
            return [None, None, -1]

        center_x = center_x // len(states['overlap']['clone'])
        center_y = center_y // len(states['overlap']['clone'])

        target_x = 0
        target_y = 0
        result = None
        # 寻找最近的食物
        min_dis = 10000
        foods = states['overlap']['food']
        for item in foods:
            dis = self.get_distance((min_clone[0], min_clone[1]), (item[0], item[1]))
            if dis < min_dis:
                target_x = item[0]
                target_y = item[1]
                min_dis = dis
        result = [target_x - min_clone[0], target_y - min_clone[1], -1]
        # 寻找最近的刺球，刺球的优先级要高于食物
        min_dis = 10000
        for item in states['overlap']['thorns']:
            dis = self.get_distance((max_clone[0], max_clone[1]), (item[0], item[1]))
            if dis < min_dis and max_clone[2] > item[2]:
                target_x = item[0]
                target_y = item[1]
                min_dis = dis
                result = [target_x - max_clone[0], target_y - max_clone[1], -1]
            pass
        # 视野中既没有食物，也没有刺球
        if target_x == 0 and target_y == 0:
            x, y = 0, 0
            if center_x < 100:
                x = 1
            else:
                x = -1
            if center_y < 100:
                y = 1
            else:
                y = -1
            result = [x, y, -1]

        for item in states['overlap']['clone']:
            if item[0] - item[2] < 10 or item[1] - item[2] < 10 or item[0] + item[2] > global_state['border'][0] - 10 or \
                    item[1] + item[2] > global_state['border'][1] - 10:
                return [random.uniform(-1, 1), random.uniform(-1, 1), -1]
        return result
        pass

    def get_distance(self, p1, p2):
        return math.pow(p2[0] - p1[0], 2) + math.pow(p2[1] - p1[1], 2)
